<?php

class T4SecurityMy
{

# --  Cookie configuration --

/**
 * Session cookie name
 * @var string
 */
protected $sSessionCookieName="seed";
/**
 * Session cookie lifetime (in seconds)
 * @var integer
 */
protected $nSessionCookieLife=31536000; // 60*60*24*365
/**
 * Session cookie path
 * @var string
 */
protected $sSessionCookieBase="/";

# -- User system configuration --

/**
 * Availible user ranks
 * @var array[int]string
 */
protected $aUserRanks = array("guest","user","admin","developer");
protected $sNewUserRank = "user";
/**
 * Guest user details ( id, login, rank )
 * @var array[string]mixed
 */
protected $aGuestUser = array("id"=>-1,"login"=>"guest","rank"=>"guest");
	
/**
 * Constructor
 */
public function __construct()
	{
	// Session engine configuration
	if(isset($this->sSessionCookieName)) ini_set('session.name',$this->sSessionCookieName);
	session_set_cookie_params($this->nSessionCookieLife,$this->sSessionCookieBase);
	}
	
/**
 * Setup security
 * * Create accounts table in database
 */
public function Install()
	{
	SQLA("CREATE TABLE `accounts` (
		`id` int(11) NOT NULL AUTO_INCREMENT,
		`login` varchar(32),
		`password` char(32),
		`rank` varchar(32),
		primary key(`id`),
		index(`login`)
		)
		");
	// TODO: ERROR: Table creating failed
	}

/**
 * Varify username and password
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return array[string]mixed User account
 */
protected function CheckUser($sLogin,$sPassword)
	{
	# Developer built-in account
	if($sLogin=="dev" and defined("X4_DEV_PASSWORD") and md5($sPassword)==X4_DEV_PASSWORD)
		return array("login"=>"dev","id"=>-101,"rank"=>"developer");
	# General account
	$sLogin = mysql_escape_string($sLogin);
	$Account = SQLI("SELECT * FROM `accounts` WHERE `login`='{$sLogin}'");
	// TODO: FIXME: Fetch
	if(!$Account) return false; // WARNING: No such user
	if(md5($sPassword)!=$Account['password']) return false; // WARNING: Incorrect password
	unset($Account['password']);
	return $Account;
	}

/**
 * Log user in and (if succeedes) starts session
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return integer User id or false if Login failed
 */
public function Login($sLogin,$sPassword)
	{
	if($Account = $this->CheckUser($sLogin,$sPassword))
		{
		$_SESSION = array();
		if(session_id())session_destroy();
		
		session_start();
		$_SESSION['user'] = $Account;
		return $Account['id'];
		}
	else
		return false;
	}
	
/**
 * Terminates user session
 */
public function Logoff()
	{
	setcookie($this->sSessionCookieName,"",-4400,$this->sSessionCookieBase);
	$_SESSION = array();
	if(session_id())session_destroy();
	return true;
	}
	
/**
 * Read current user
 */
public function Authenticate()
	{
	if(!session_id()) session_start();
	if(!isset($_SESSION['user'])) $_SESSION['user'] = $this->aGuestUser;	
	}
	
/**
 * Get Current User
 * @return array[string]mixed User details structure
 */
public function getCurrentUser()
	{
	$this->Authenticate();
	return $_SESSION['user'];
	}
	
/**
 * Adds new user
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return bool Succeeds or failed
 */
public function Register($sLogin,$sPassword)
	{
	// Check login availibility
	if(!$this->CheckLoginFree($sLogin)) return false;
	
	$sLogin = mysql_escape_string($sLogin);
	$sPasswordHash = md5($sPassword);
	$bCheck = SQLA("INSERT INTO `accounts` (`login`,`password`,`rank`) VALUES ('{$sLogin}','{$sPasswordHash}','{$this->sNewUserRank}')");
	return $bCheck;
	}
	
/**
 * Check wether login free or not
 *
 * @param string $sLogin
 * @return bool
 */
public function CheckLoginFree($sLogin)
	{
	// Reserved logins
	if($sLogin==$this->aGuestUser['login'] or $sLogin=="dev") return false;
	
	$sLogin = mysql_escape_string($sLogin);
	$sQuery = "SELECT COUNT(*) FROM `accounts` WHERE `login` = '{$sLogin}'";
	$LoginUsed = SQLF($sQuery);
	return (intval($LoginUsed)==0);
	}

/**
 * Check if current user has required access level
 * @param mixed $mLevel Requested access level string or integer
 * @return boolean
 */
public function CheckAccessLevel($mLevel)
	{
	if(is_string($mLevel)) $mLevel = array_search($mLevel,$this->aUserRanks);
	if($mLevel===false) return false; // ERROR: Non-existing level requested
	if(!is_int($mLevel)) return false; // ERROR: Wrong requested level format
	$aCurrentUser = $this->getCurrentUser();
	$iUserLevel = array_search($aCurrentUser['rank'],$this->aUserRanks);
	return ($iUserLevel >= $mLevel);
	}

public function lists()
	{
	$sQuery = "SELECT `id`, `login`, `rank` FROM `accounts`";
	return SQLS_X($sQuery,"id");
	}
	
public function load($id)
	{
	$sQuery = "SELECT `id`, `login`, `rank` FROM `accounts` WHERE `id`=".SQLEV($id);
	return SQLI($sQuery,"id");	
	}
	
public function save($aData)
	{
	# Id
	$id = $aData['id'];
	unset($aData['id']);
	# Password
	if(isset($aData['password']))
		$aData['password'] = md5($aData['password']);
	# Prepare request
	$sQuery = "UPDATE `accounts` SET ".SQLEPS($aData)." WHERE `id`=".SQLEV($id);
	# Run request
	$bResult = SQLA($sQuery); 
	return $bResult;
	}
}
?>